home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Overload Trio 2
/
Shareware Overload Trio Volume 2 (Chestnut CD-ROM).ISO
/
dir37
/
ushell.zip
/
SHELL
/
SH7.C
< prev
next >
Wrap
C/C++ Source or Header
|
1990-02-19
|
33KB
|
1,828 lines
/* MS-DOS SHELL - Internal Command Processing
*
* MS-DOS SHELL - Copyright (c) 1990 Data Logic Limited and Charles Forsyth
*
* This code is based on (in part) the shell program written by Charles
* Forsyth and is subject to the following copyright restrictions:
*
* 1. Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice is duplicated in the
* source form and the copyright notice in file sh6.c is displayed
* on entry to the program.
*
* 2. The sources (or parts thereof) or objects generated from the sources
* (or parts of sources) cannot be sold under any circumstances.
*
* $Header: sh7.c 1.1 90/01/29 17:46:25 MS_user Exp $
*
* $Log: sh7.c $
* Revision 1.1 90/01/29 17:46:25 MS_user
* Initial revision
*
*
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <process.h>
#include <dos.h>
#include <signal.h>
#include <errno.h>
#include <setjmp.h>
#include <ctype.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <limits.h>
#include <stdarg.h>
#include "sh.h"
#define SECS 60L
#define MINS 3600L
#define IS_OCTAL(a) (((a) >= '0') && ((a) <= '7'))
/* Definitions for test */
#define END_OF_INPUT 0
#define FILE_READABLE 1
#define FILE_WRITABLE 2
#define FILE_REGULAR 3
#define FILE_DIRECTORY 4
#define FILE_NONZERO 5
#define FILE_TERMINAL 6
#define STRING_ZERO 7
#define STRING_NONZERO 8
#define STRING_EQUAL 9
#define STRING_NOTEQUAL 10
#define NUMBER_EQUAL 11
#define NUMBER_NOTEQUAL 12
#define NUMBER_EQ_GREAT 13
#define NUMBER_GREATER 14
#define NUMBER_EQ_LESS 15
#define NUMBER_LESS 16
#define UNARY_NOT 17
#define BINARY_AND 18
#define BINARY_OR 19
#define LPAREN 20
#define RPAREN 21
#define OPERAND 22
#define FILE_EXECUTABLE 23
#define FILE_USER 24
#define FILE_GROUP 25
#define FILE_TEXT 26
#define FILE_BLOCK 27
#define FILE_CHARACTER 28
#define FILE_FIFO 29
#define UNARY_OP 1
#define BINARY_OP 2
#define B_UNARY_OP 3
#define B_BINARY_OP 4
#define PAREN 5
static struct test_op {
char *op_text;
short op_num;
short op_type;
} test_ops[] = {
{"-r", FILE_READABLE, UNARY_OP},
{"-w", FILE_WRITABLE, UNARY_OP},
{"-x", FILE_EXECUTABLE, UNARY_OP},
{"-f", FILE_REGULAR, UNARY_OP},
{"-d", FILE_DIRECTORY, UNARY_OP},
{"-s", FILE_NONZERO, UNARY_OP},
{"-t", FILE_TERMINAL, UNARY_OP},
{"-z", STRING_ZERO, UNARY_OP},
{"-n", STRING_NONZERO, UNARY_OP},
{"=", STRING_EQUAL, BINARY_OP},
{"!=", STRING_NOTEQUAL, BINARY_OP},
{"-eq", NUMBER_EQUAL, BINARY_OP},
{"-ne", NUMBER_NOTEQUAL, BINARY_OP},
{"-ge", NUMBER_EQ_GREAT, BINARY_OP},
{"-gt", NUMBER_GREATER, BINARY_OP},
{"-le", NUMBER_EQ_LESS, BINARY_OP},
{"-lt", NUMBER_LESS, BINARY_OP},
{"!", UNARY_NOT, B_UNARY_OP},
{"-a", BINARY_AND, B_BINARY_OP},
{"-o", BINARY_OR, B_BINARY_OP},
{"(", LPAREN, PAREN},
{")", RPAREN, PAREN},
#ifdef S_IFCHR
{"-c", FILE_CHARACTER, UNARY_OP},
#endif
#ifdef S_IFBLK
{"-b", FILE_BLOCK, UNARY_OP},
#endif
#ifdef S_ISUID
{"-u", FILE_USER, UNARY_OP},
#endif
#ifdef S_ISGID
{"-g", FILE_GROUP, UNARY_OP},
#endif
#ifdef S_ISVTX
{"-k", FILE_TEXT, UNARY_OP},
#endif
#ifdef S_IFIFO
{"-p", FILE_FIFO, UNARY_OP},
#endif
{(char *)NULL, NULL, NULL}
};
static int expr (int);
static int bexpr (int);
static int primary (int);
static int lex (char *);
static long num (char *);
static void syntax (void);
static int dolabel (C_Op *);
static int dochdir (C_Op *);
static int dodrive (C_Op *);
static int doshift (C_Op *);
static int doumask (C_Op *);
static int dodot (C_Op *);
static int doecho (C_Op *);
static int dogetopt (C_Op *);
static int dopwd (C_Op *);
static int doswap (C_Op *);
static int dounset (C_Op *);
static int dotype (C_Op *);
static int dotest (C_Op *);
static int dover (C_Op *);
static int doread (C_Op *);
static int doeval (C_Op *);
static int dotrap (C_Op *);
static int getsig (char *);
static int dobreak (C_Op *);
static int docontinue (C_Op *);
static int brkcontin (char *, int);
static int doexit (C_Op *);
static int doexec (C_Op *);
static int doreturn (C_Op *);
static int doexport (C_Op *);
static int domsdos (C_Op *);
static int doreadonly (C_Op *);
static int doset (C_Op *);
static int dohistory (C_Op *);
static void setsig (int, int (*)());
static int rdexp (char **, int, char *);
static void v1_putsn (char *, int);
static char **test_alist;
static struct test_op *test_op;
static jmp_buf test_jmp;
/*
* built-in commands: doX
*/
static int dolabel (t)
C_Op *t;
{
return 0;
}
/*
* Getopt - split arguments. getopts pattern args
*/
static int dogetopt (t)
register C_Op *t;
{
int argc;
char **argv = t->words;
int c;
/* Count arguments */
optind = 1; /* Reset the optind flag */
opterr = 1; /* Reset the error flag */
for (argc = 0; t->words[argc] != (char *)NULL; argc++);
if (argc < 2)
{
S_puts ("usage: getopt legal-args $*\n");
return 2;
}
argc -= 2;
argv += 2;
/* Scan each argument */
while ((c = getopt (argc, argv, t->words[1])) != EOF)
{
if (c == '?')
return 2;
v1printf ("-%c ", c);
/* Check for addition parameter */
if (*(strchr (t->words[1], c) + 1) == ':')
{
v1_puts (optarg);
v1_putc (SP);
}
}
v1_puts ("-- ");
argv += optind;
while (optind++ < argc)
{
v1_puts (*argv++);
v1_putc ((char)((optind == argc) ? NL : SP));
}
return 0;
}
/*
* Echo the parameters
*/
static int doecho (t)
register C_Op *t;
{
int n = 1;
int no_eol = 0; /* No EOL */
char *ip; /* Input pointer */
int c_val; /* Current character */
char c;
bool end_s;
char *cp = e.linep;
/* Always leave room for NL */
char *ep = &e.linep[LINE_MAX - 3];
while ((ip = t->words[n++]) != (char *)NULL)
{
if ((n == 2) && (strcmp (ip, "-n") == 0))
{
no_eol++;
continue;
}
/* Process the string */
end_s = FALSE;
do
{
/* Any special character processing ? */
if ((c = *(ip++)) == '\\')
{
if ((c_val = Process_Escape (&ip)) == -1)
{
no_eol = 1;
continue;
}
c = (char)c_val;
}
/* End of string - check to see if a space if required */
else if (c == 0)
{
end_s = TRUE;
if (t->words[n] != (char *)NULL)
c = SP;
else
continue;
}
/* Output the character */
if (cp < ep)
*(cp++) = c;
else
{
v1_putsn (e.linep, (int)(cp - e.linep));
cp = e.linep;
}
} while (!end_s);
}
/* Is EOL required ? */
if (!no_eol)
*(cp++) = NL;
/* Flush buffer */
if ((n = (int)(cp - e.linep)))
v1_putsn (e.linep, n);
return 0;
}
/*
* Process_Escape - Convert an escaped character to a binary value.
*
* Returns the binary value and updates the string pointer.
*/
int Process_Escape (cp)
char **cp; /* Pointer to character */
{
int c_val = **cp; /* Current character */
if (c_val)
(*cp)++;
/* Process escaped characters */
switch (c_val)
{
case 'b': /* Backspace */
return 0x08;
case 'f': /* Form Feed */
return 0x0c;
case 'v': /* Vertical Tab */
return 0x0b;
case 'n': /* New Line */
return 0x0a;
case 'r': /* Carriage return */
return 0x0d;
case 't': /* Forward tab */
return 0x09;
case '\\': /* Backslash */
return '\\';
case 'c': /* no eol */
return -1;
}
/* Check for an octal string */
if ((c_val >= 0) && (c_val < 8))
{
while ((IS_OCTAL (**cp)))
c_val = (c_val * 8) + *((*cp)++) - '0';
return c_val;
}
return c_val;
}
/*
* Display the current version
*/
static int dover (t)
C_Op *t;
{
v1printf (Copy_Right1, _osmajor, _osminor);
v1a_puts (Copy_Right2);
return 0;
}
static char *swap_device[] = {"disk", "extend", "expand"};
/*
* Modify swapping information: swap options
*/
static int doswap (t)
register C_Op *t;
{
register int n = 1;
char *cp;
/* Display current values ? */
if (t->words[1] == (char *)NULL)
{
if (Swap_Mode == SWAP_OFF)
v1a_puts ("Swapping disabled");
else
{
register int j;
v1_puts ("Swap devices: ");
for (j = 0, n = 1; j < 3; ++j, n <<= 1)
{
if (Swap_Mode & n)
{
v1printf ("%s ", swap_device[j]);
if (n == SWAP_EXTEND)
v1printf ("(0x%.6lx) ", SW_EMstart);
}
}
v1_putc (NL);
}
return 0;
}
/* Set up new values */
Swap_Mode = SWAP_OFF;
while ((cp = t->words[n++]) != (char *)NULL)
{
if (strcmp (cp, "off") == 0)
Swap_Mode = SWAP_OFF;
else if (strcmp (cp, "on") == 0)
Swap_Mode = SWAP_DISK | SWAP_EXPAND | SWAP_EXTEND;
/* Scan for valid arguments */
else
{
register int j, k;
for (j = 0, k = 1; j < 3; ++j, k <<= 1)
{
if (strcmp (cp, swap_device[j]) == 0)
{
Swap_Mode |= k;
/* If extended memory, they can specify the start address as a hex number */
if (k == SWAP_EXTEND)
{
char *sp;
long start;
/* Check for not changed */
if ((sp = t->words[n]) == (char *)NULL)
break;
/* Convert hex number */
start = strtol (sp, &sp, 16);
/* If not completely a hex number, ignore */
if (*sp)
break;
/* Set used and saved new value */
SW_EMstart = start;
++n;
if ((SW_EMstart < 0x100000L) ||
(SW_EMstart > 0xf00000L))
SW_EMstart = 0x100000L;
v1printf ("Extend memory start set to 0x%.6lx\n",
SW_EMstart);
}
break;
}
}
}
}
return 0;
}
/*
* Output the current path: pwd
*/
static int dopwd (t)
register C_Op *t;
{
v1a_puts (C_dir->value);
return 0;
}
/*
* Unset a variable: unset <flag..> <variable name...>
*/
static int dounset (t)
register C_Op *t;
{
register int n = 1;
while (t->words[n] != (char *)NULL)
unset (t->words[n++], FALSE);
return 0;
}
/* Delete a variable or function. If all is set, system variables can be
* deleted. This is used to delete the trap functions
*/
void unset (cp, all)
register char *cp;
bool all;
{
register Var_List *vp;
register Var_List *pvp;
/* Unset a flag */
if (*cp == '-')
{
while (*(++cp) != 0)
{
if (islower (*cp))
FL_CLEAR (*cp);
}
setdash ();
return;
}
/* Ok - unset a variable and not a local value */
if (!all && !(isalpha (*cp)))
return;
/* Check in list */
pvp = (Var_List *)NULL;
for (vp = vlist; (vp != (Var_List *)NULL) && !eqname (vp->name, cp);
vp = vp->next)
pvp = vp;
/* If not found, delete the function if it exists */
if (vp == (Var_List *)NULL)
{
Fun_Ops *fp;
if ((fp = Fun_Search (cp)) != (Fun_Ops *)NULL)
Save_Function (fp->tree, TRUE);
return;
}
/* Error if read-only */
if (vp->status & (RONLY | PONLY))
{
if ((cp = strchr (vp->name, '=')) != (char *)NULL)
*cp = 0;
S_puts (vp->name);
if (cp != (char *)NULL)
*cp = '=';
S_puts ((vp->status & PONLY) ? ": cannot unset\n" : " is read-only\n");
return;
}
/* Delete it */
if (vp->status & GETCELL)
DELETE (vp->name);
if (pvp == (Var_List *)NULL)
vlist = vp->next;
else
pvp->next = vp->next;
DELETE (vp);
}
/*
* Execute a test: test <arguments>
*/
static int dotest (t)
register C_Op *t;
{
int st = 0;
if (*(test_alist = &t->words[1]) == (char *)NULL)
return 1;
/* If [ <arguments> ] form, check for end ] and remove it */
if (strcmp (t->words[0], "[") == 0)
{
while (t->words[++st] != (char *)NULL)
;
if (strcmp (t->words[--st], "]") != 0)
{
print_error ("test: missing ']'\n");
return 1;
}
else
t->words[st] = (char *)NULL;
}
/* Set abort address */
if (setjmp (test_jmp))
return 1;
st = !expr (lex (*test_alist));
if (*(++test_alist) != (char *)NULL)
syntax ();
return (st);
}
static int expr (n)
int n;
{
int res;
if (n == END_OF_INPUT)
syntax ();
res = bexpr (n);
if (lex (*(++test_alist)) == BINARY_OR)
return expr (lex (*(++test_alist))) || res;
test_alist--;
return res;
}
static int bexpr (n)
int n;
{
int res;
if (n == END_OF_INPUT)
syntax ();
res = primary (n);
if (lex (*(++test_alist)) == BINARY_AND)
return bexpr (lex (*(++test_alist))) && res;
test_alist--;
return res;
}
static int primary (n)
int n;
{
register char *opnd1, *opnd2;
struct stat s;
int res;
if (n == END_OF_INPUT)
syntax ();
if (n == UNARY_NOT)
return !expr (lex (*(++test_alist)));
if (n == LPAREN)
{
res = expr (lex (*(++test_alist)));
if (lex (*(++test_alist)) != RPAREN)
syntax ();
return res;
}
if (n == OPERAND)
{
opnd1 = *test_alist;
(void) lex (*(++test_alist));
if ((test_op != (C_Op *)NULL) && test_op->op_type == BINARY_OP)
{
struct test_op *op = test_op;
if ((opnd2 = *(++test_alist)) == (char *)NULL)
syntax ();
switch (op->op_num)
{
case STRING_EQUAL:
return strcmp (opnd1, opnd2) == 0;
case STRING_NOTEQUAL:
return strcmp (opnd1, opnd2) != 0;
case NUMBER_EQUAL:
return num (opnd1) == num (opnd2);
case NUMBER_NOTEQUAL:
return num (opnd1) != num (opnd2);
case NUMBER_EQ_GREAT:
return num (opnd1) >= num (opnd2);
case NUMBER_GREATER:
return num (opnd1) > num (opnd2);
case NUMBER_EQ_LESS:
return num (opnd1) <= num (opnd2);
case NUMBER_LESS:
return num (opnd1) < num (opnd2);
}
}
test_alist--;
return strlen (opnd1) > 0;
}
/* unary expression */
if (test_op->op_type != UNARY_OP || *++test_alist == 0)
syntax ();
switch (n)
{
case STRING_ZERO:
return strlen (*test_alist) == 0;
case STRING_NONZERO:
return strlen (*test_alist) != 0;
case FILE_READABLE:
return access (*test_alist, R_OK) == 0;
case FILE_WRITABLE:
return access (*test_alist, W_OK) == 0;
case FILE_EXECUTABLE:
return access (*test_alist, X_OK) == 0;
case FILE_REGULAR:
return stat (*test_alist, &s) == 0 && S_ISREG(s.st_mode);
case FILE_DIRECTORY:
return stat (*test_alist, &s) == 0 && S_ISDIR(s.st_mode);
case FILE_NONZERO:
return stat (*test_alist, &s) == 0 && (s.st_size > 0L);
case FILE_TERMINAL:
return isatty ((int)num (*test_alist));
#ifdef S_ISUID
case FILE_USER:
return stat (*test_alist, &s) == 0 && (s.st_mode & S_ISUID);
#endif
#ifdef S_ISGID
case FILE_GROUP:
return stat (*test_alist, &s) == 0 && (s.st_mode & S_ISGID);
#endif
#ifdef S_ISVTX
case FILE_TEXT:
return stat (*test_alist, &s) == 0 && (s.st_mode & S_ISVTX);
#endif
#ifdef S_IFBLK
case FILE_BLOCK:
return stat (*test_alist, &s) == 0 && S_ISBLK(s.st_mode);
#endif
#ifdef S_IFCHR
case FILE_CHARACTER:
return stat (*test_alist, &s) == 0 && S_ISCHR(s.st_mode);
#endif
#ifdef S_IFIFO
case FILE_FIFO:
return stat (*test_alist, &s) == 0 && S_ISFIFO(s.st_mode);
#endif
}
}
static int lex (s)
register char *s;
{
register struct test_op *op = test_ops;
if (s == (char *)NULL)
return END_OF_INPUT;
while (op->op_text)
{
if (strcmp (s, op->op_text) == 0)
{
test_op = op;
return op->op_num;
}
op++;
}
test_op = (struct test_op *)NULL;
return OPERAND;
}
/*
* Get a long numeric value
*/
static long num (s)
register char *s;
{
char *ep;
long l = strtol (s, &ep, 10);
if (!*s || *ep)
syntax ();
return l;
}
/*
* test syntax error - abort
*/
static void syntax ()
{
print_error ("test: syntax error\n");
longjmp (test_jmp, 1);
}
/*
* Select a new drive: x:
*
* Select the drive, get the current directory and check that we have
* actually selected the drive
*/
static int dodrive (t)
register C_Op *t;
{
unsigned int cdrive;
unsigned int ndrive = tolower (**t->words) - 'a' + 1;
_dos_setdrive (ndrive, &cdrive);
Getcwd ();
_dos_getdrive (&cdrive);
return (ndrive == cdrive) ? 0 : 1;
}
/*
* Select a new directory: cd
*/
static int dochdir (t)
register C_Op *t;
{
char *p;
char *nd;
register char *cp;
int first = 0;
unsigned int dummy;
unsigned int cdrive;
/* If restricted shell - illegal */
if (check_rsh ("cd"))
return 1;
/* Use default ? */
if (((p = t->words[1]) == (char *)NULL) &&
((p = lookup (home, FALSE)->value) == null))
{
print_error ("cd: no home directory\n");
return 1;
}
/* Save the current drive */
_dos_getdrive (&cdrive);
/* Scan for the directory. If there is not a / or : at start, use the
* CDPATH variable
*/
cp = (*p == '/') ? null : lookup ("CDPATH", FALSE)->value;
cp = (*(p + 1) == ':') ? null : cp;
do
{
cp = path_append (cp, p, e.linep);
/* Check for new disk drive */
nd = e.linep;
if (*(nd+ 1) == ':')
{
_dos_setdrive (tolower (*nd) - 'a' + 1, &dummy);
nd += 2;
}
/* Was the change successful? */
if ((!*nd) || (chdir (nd) == 0))
{
/* OK - reset the current directory (in the shell) and display the new
* path if appropriate
*/
Getcwd ();
if (first || (strchr (p, '/') != (char *)NULL))
dopwd (t);
return 0;
}
first = 1;
} while (cp != (char *)NULL);
/* Restore our original drive and restore directory info */
_dos_setdrive (cdrive, &dummy);
Getcwd ();
print_error ("%s: bad directory\n", p);
return 1;
}
/*
* Extract the next path from a string and build a new path from the
* extracted path and a file name
*/
char *path_append (s1, s2, si)
register char *s1; /* Path string */
register char *s2; /* File name string */
char *si; /* Output path */
{
register char *s;
s = si;
while (*s1 && *s1 != ';')
*s++ = *s1++;
if ((si != s) && (*(s - 1) != '/'))
*s++ = '/';
*s = '\0';
if (s2 != (char *)NULL)
strcpy (s, s2);
return (*s1 ? ++s1 : (char *)NULL);
}
/*
* Execute a shift command: shift <n>
*/
static int doshift (t)
register C_Op *t;
{
register int n;
n = (t->words[1] != (char *)NULL) ? getn (t->words[1]) : 1;
if (dolc < n)
{
print_error ("sh: nothing to shift\n");
return 1;
}
dolv[n] = dolv[0];
dolv += n;
dolc -= n;
setval (lookup ("#", TRUE), putn (dolc));
return 0;
}
/*
* Execute a umask command: umask <n>
*/
static int doumask (t)
register C_Op *t;
{
register int i;
register char *cp;
if ((cp = t->words[1]) == (char *)NULL)
{
i = umask (0);
umask (i);
v1printf ("%o\n", i);
}
else
{
i = 0;
while (IS_OCTAL (*cp))
i = i * 8 + (*(cp++) - '0');
umask (i);
}
return 0;
}
/*
* Execute an exec command: exec <arguments>
*/
static int doexec (t)
register C_Op *t;
{
register int i;
jmp_buf ex;
int *ofail;
t->ioact = (IO_Actions **)NULL;
for (i = 0; (t->words[i] = t->words[i + 1]) != (char *)NULL; i++)
;
if (i == 0)
return 0;
execflg = 1;
ofail = failpt;
/* Set execute function recursive level to zero */
Execute_stack_depth = 0;
if (setjmp (failpt = ex) == 0)
execute (t, NOPIPE, NOPIPE, FEXEC);
failpt = ofail;
execflg = 0;
return 1;
}
/*
* Execute a script in the current shell
*/
static int dodot (t)
C_Op *t;
{
register int i;
register char *sp;
char *cp;
if ((cp = t->words[1]) == (char *)NULL)
return 0;
sp = any ('/', cp) ? null : path->value;
do
{
sp = path_append (sp, cp, e.linep);
if ((i = O_for_execute (e.linep)) >= 0)
{
exstat = 0;
next (remap (i));
return exstat;
}
} while (sp != (char *)NULL);
print_error ("%s: not found\n", cp);
return 1;
}
/*
* Read from standard input into a variable list
*/
static int doread (t)
C_Op *t;
{
register char *cp, **wp;
register int nb;
if (t->words[1] == (char *)NULL)
{
print_error ("Usage: read name ...\n");
return 1;
}
for (wp = t->words + 1; *wp != (char *)NULL; wp++)
{
for (cp = e.linep; cp < e.eline - 1; cp++)
{
if (((nb = read (STDIN_FILENO, cp, 1)) != 1) || (*cp == NL) ||
((wp[1] != (char *)NULL) && any (*cp, ifs->value)))
break;
}
*cp = 0;
if (nb <= 0)
break;
setval (lookup (*wp, TRUE), e.linep);
}
return (nb <= 0);
}
/*
* Evaluate an expression
*/
static int doeval (t)
register C_Op *t;
{
return RUN (awordlist, t->words + 1, wdchar);
}
/*
* Execute a trap
*/
static int dotrap (t)
register C_Op *t;
{
register int n, i;
register int resetsig;
char tval[10];
char *cp;
if (t->words[1] == (char *)NULL)
{
/* Display trap - look up each trap and print those we find */
for (i = 0; i < NSIG; i++)
{
sprintf (tval, "~%d", i);
if ((cp = lookup (tval, FALSE)->value) != null)
{
v1printf ("%u: ", i);
v1a_puts (cp);
}
}
return 0;
}
resetsig = isdigit (*t->words[1]); /* Reset signal? */
for (i = resetsig ? 1 : 2; t->words[i] != (char *)NULL; ++i)
{
/* Generate the variable name */
sprintf (tval, "~%d", (n = getsig (t->words[i])));
if (n == -1)
return 1;
unset (tval, TRUE);
/* Re-define signal processing */
if (!resetsig)
{
if (*t->words[1] != '\0')
{
setval (lookup (tval, TRUE), t->words[1]);
setsig (n, sig);
}
else
setsig (n, SIG_IGN);
}
/* Clear signal processing */
else if (talking)
{
if (n == SIGINT)
setsig (n, onintr);
else
#ifdef SIGQUIT
setsig (n, n == SIGQUIT ? SIG_IGN : SIG_DFL);
#else
setsig (n, SIG_DFL);
#endif
}
else
setsig (n, SIG_DFL);
}
return 0;
}
/*
* Get a signal number
*/
static int getsig (s)
char *s;
{
register int n;
if (((n = getn (s)) < 0) || (n >= NSIG))
{
print_error ("trap: bad signal number\n");
n = -1;
}
return n;
}
/*
* Set up a signal function
*/
static void setsig (n, f)
register int n;
int (*f)();
{
if (n == 0)
return;
if ((signal (n, SIG_IGN) != SIG_IGN) || (ourtrap & (1L << n)))
{
ourtrap |= (1L << n);
signal (n, f);
}
}
/* Convert a string to a number */
int getn (as)
char *as;
{
char *s;
int n = (int)strtol (as, &s, 10);
if (*s)
print_error ("%s: bad number\n", as);
return n;
}
/*
* BREAK and CONTINUE processing
*/
static int dobreak (t)
C_Op *t;
{
return brkcontin (t->words[1], BC_BREAK);
}
static int docontinue (t)
C_Op *t;
{
return brkcontin (t->words[1], BC_CONTINUE);
}
static int brkcontin (cp, val)
register char *cp;
int val;
{
register Break_C *Break_Loc;
register int nl;
if ((nl = (cp == (char *)NULL) ? 1 : getn (cp)) <= 0)
nl = 999;
do
{
if ((Break_Loc = Break_List) == (Break_C *)NULL)
break;
Break_List = Break_Loc->nextlev;
} while (--nl);
if (nl)
{
print_error ("sh: bad break/continue level\n");
return 1;
}
longjmp (Break_Loc->brkpt, val);
/* NOTREACHED */
}
/*
* Exit function
*/
static int doexit (t)
C_Op *t;
{
Break_C *SShell_Loc = SShell_List;
execflg = 0;
/* Set up error codes */
if (t->words[1] != (char *)NULL)
{
exstat = getn (t->words[1]);
setval (lookup ("?", TRUE), t->words[1]);
}
/* Are we in a subshell. Yes - do a longjmp instead of an exit */
if (SShell_Loc != (Break_C *)NULL)
{
SShell_List = SShell_Loc->nextlev;
longjmp (SShell_Loc->brkpt, 1);
}
leave ();
return 1;
}
/*
* Function return - set exit value and return via a long jmp
*/
static int doreturn (t)
C_Op *t;
{
Break_C *Return_Loc = Return_List;
if (t->words[1] != (char *)NULL)
setval (lookup ("?", TRUE), t->words[1]);
/* If the return address is defined - return to it. Otherwise, return
* the value
*/
if (Return_Loc != (Break_C *)NULL)
{
Return_List = Return_Loc->nextlev;
longjmp (Return_Loc->brkpt, 1);
}
return getn (t->words[1]);
}
/*
* MSDOS, EXPORT and READONLY functions
*/
static int doexport (t)
C_Op *t;
{
return rdexp (t->words + 1, EXPORT, "export ");
}
static int doreadonly (t)
C_Op *t;
{
return rdexp (t->words + 1, RONLY, "readonly ");
}
static int domsdos (t)
C_Op *t;
{
return rdexp (t->words + 1, C_MSDOS, "msdos ");
}
static int rdexp (wp, key, tstring)
register char **wp;
int key;
char *tstring;
{
char *cp;
bool valid;
if (*wp != (char *)NULL)
{
for (; *wp != (char *)NULL; wp++)
{
cp = *wp;
valid = TRUE;
/* Check for a valid name */
if (!isalpha (*(cp++)))
valid = FALSE;
else
{
while (*cp)
{
if (!isalnum (*(cp++)))
{
valid = FALSE;
break;
}
}
}
/* If valid - update, otherwise print a message */
if (valid)
s_vstatus (lookup (*wp, TRUE), key);
else
print_error ("%s: bad identifier\n", *wp);
}
}
else
{
register Var_List *vp;
for (vp = vlist; vp != (Var_List *) NULL; vp = vp->next)
{
if ((vp->status & key) && isalpha (*vp->name))
{
v1_puts (tstring);
v1_putsn (vp->name, (int)(findeq (vp->name) - vp->name));
v1_putc (NL);
}
}
}
return 0;
}
/*
* Sort Compare function for displaying variables
*/
int sort_compare (s1, s2)
char **s1;
char **s2;
{
return strcmp (*s1, *s2);
}
/*
* Set function
*/
static int doset (t)
register C_Op *t;
{
register Var_List *vp;
register char *cp;
register int n, j;
Fun_Ops *fp;
char sign;
char **list;
/* Display ? */
if ((cp = t->words[1]) == (char *)NULL)
{
/* Count the number of entries to print */
for (n = 0, vp = vlist; vp != (Var_List *)NULL; vp = vp->next)
{
if (isalnum (*vp->name))
n++;
}
/* Build a local array of name */
list = (char **)space (sizeof (char *) * n);
for (n = 0, vp = vlist; vp != (Var_List *)NULL; vp = vp->next)
{
if (isalnum (*vp->name))
{
if (list == (char **)NULL)
v1a_puts (vp->name);
else
list[n++] = vp->name;
}
}
/* Sort them and then print */
if (list != (char **)NULL)
{
qsort (list, n, sizeof (char *), sort_compare);
for (j = 0; j < n; j++)
v1a_puts (list[j]);
DELETE (list);
}
/* Print the list of functions */
for (fp = fun_list; fp != (Fun_Ops *)NULL; fp = fp->next)
Print_ExTree (fp->tree);
return 0;
}
/* Set/Unset a flag ? */
if (((sign = *cp) == '-') || (*cp == '+'))
{
for (n = 0; (t->words[n] = t->words[n + 1]) != (char *)NULL; n++)
;
for (; *cp; cp++)
{
if (*cp == 'r')
{
print_error ("set: -r bad option\n");
return 1;
}
if (*cp == 'e')
{
if (!talking)
{
if (sign == '-')
FL_SET ('e');
else
FL_CLEAR ('e');
}
}
else if (islower (*cp))
{
if (sign == '-')
FL_SET (*cp);
else
FL_CLEAR (*cp);
}
}
setdash ();
}
/* Set up parameters ? */
if (t->words[1])
{
t->words[0] = dolv[0];
for (n = 1; t->words[n] != (char *)NULL; n++)
setarea ((char *)t->words[n], 0);
dolc = n-1;
dolv = t->words;
setval (lookup ("#", TRUE), putn (dolc));
setarea ((char *)(dolv - 1), 0);
}
return 0;
}
/*
* History functions - display, initialise, enable, disable
*/
static int dohistory (t)
C_Op *t;
{
char *cp;
if (!talking)
return 1;
if ((cp = t->words[1]) == (char *)NULL)
Display_History ();
else if (strcmp (cp, "-i") == 0)
Clear_History ();
else if (strcmp (cp, "-d") == 0)
History_Enabled = FALSE;
else if (strcmp (cp, "-e") == 0)
History_Enabled = TRUE;
return 0;
}
/*
* Type fucntion: For each name, indicate how it would be interpreted
*/
static char *type_ext[] = {
"", ".exe", ".com", ".sh"
};
static int dotype (t)
register C_Op *t;
{
register char *sp; /* Path pointers */
char *cp;
char *ep;
char *xp; /* In file name pointers */
char *xp1;
int n = 1; /* Argument count */
int i, fp;
bool found; /* Found flag */
while ((cp = t->words[n++]) != (char *)NULL)
{
sp = any ('/', cp) ? null : path->value;
found = FALSE;
do
{
sp = path_append (sp, cp, e.linep);
ep = &e.linep[strlen (e.linep)];
/* Get start of file name */
if ((xp1 = strrchr (e.linep, '/')) == (char *)NULL)
xp1 = e.linep;
else
++xp1;
/* Look up all 4 types */
for (i = 0; (i < 4) && !found; i++)
{
strcpy (ep, type_ext[i]);
if (access (e.linep, F_OK) == 0)
{
/* If no extension or .sh extension, check for shell script */
if (((xp = strchr (xp1, '.')) == (char *)NULL) ||
(stricmp (xp, ".sh") == 0))
{
if ((fp = Check_Script (e.linep)) < 0)
continue;
S_close (fp, TRUE);
}
else if ((stricmp (xp, ".exe") != 0) &&
(stricmp (xp, ".com") != 0))
continue;
print_error ("%s is %s\n", cp, e.linep);
found = TRUE;
}
}
} while ((sp != (char *)NULL) && !found);
if (!found)
print_error ("%s not found\n", cp);
}
return 0;
}
/* Table of internal commands */
static struct builtin builtin[] = {
".", dodot,
":", dolabel,
"[", dotest,
"break", dobreak,
"cd", dochdir,
"continue", docontinue,
"echo", doecho,
"eval", doeval,
"exec", doexec,
"exit", doexit,
"export", doexport,
"getopt", dogetopt,
"history", dohistory,
"msdos", domsdos,
"pwd", dopwd,
"read", doread,
"readonly", doreadonly,
"return", doreturn,
"set", doset,
"shift", doshift,
"swap", doswap,
"test", dotest,
"trap", dotrap,
"type", dotype,
"umask", doumask,
"unset", dounset,
"ver", dover,
(char *)NULL,
};
/*
* Look up a built in command
*/
int (*inbuilt (s))()
register char *s;
{
register struct builtin *bp;
if ((strlen (s) == 2) && isalpha (*s) && (*s != '_') && (*(s + 1) == ':'))
return dodrive;
for (bp = builtin; bp->command != (char *)NULL; bp++)
{
if (stricmp (bp->command, s) == 0)
return bp->fn;
}
return NULL;
}
/* Write to stdout functions - printf, fputs, fputc, and a special */
/*
* Equivalent of printf without using streams
*/
void v1printf (fmt)
char *fmt;
{
va_list ap;
char x[100];
va_start (ap, fmt);
vsprintf (x, fmt, ap);
v1_puts (x);
va_end (ap);
}
/*
* Write string to STDOUT
*/
void v1_puts (s)
char *s;
{
write (STDOUT_FILENO, s, strlen (s));
}
/*
* Write string to STDOUT with a NL at end
*/
void v1a_puts (s)
char *s;
{
char c = NL;
write (STDOUT_FILENO, s, strlen (s));
write (STDOUT_FILENO, &c, 1);
}
/*
* Write n characters to STDOUT
*/
static void v1_putsn (s, n)
char *s;
int n;
{
write (STDOUT_FILENO, s, n);
}
/*
* Write 1 character to STDOUT
*/
void v1_putc (c)
char c;
{
write (STDOUT_FILENO, &c, 1);
}